package com.dobbinsoft.iotechn.device.service.biz;

import com.aliyun.vod.upload.common.MD5Util;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.dobbinsoft.iotechn.core.constant.Const;
import com.dobbinsoft.iotechn.core.exception.ServiceException;
import com.dobbinsoft.iotechn.data.compent.CacheComponent;
import com.dobbinsoft.iotechn.device.api.biz.DeviceBizService;
import com.dobbinsoft.iotechn.device.constant.DeviceConst;
import com.dobbinsoft.iotechn.device.domain.DeviceDO;
import com.dobbinsoft.iotechn.device.domain.DeviceDataDO;
import com.dobbinsoft.iotechn.device.domain.ProductDataDO;
import com.dobbinsoft.iotechn.device.entity.DeviceDataSnapshotEntity;
import com.dobbinsoft.iotechn.device.entity.DeviceSessionDataEntity;
import com.dobbinsoft.iotechn.device.enums.DeviceAuthType;
import com.dobbinsoft.iotechn.device.enums.DeviceStatusType;
import com.dobbinsoft.iotechn.device.exception.DeviceExceptionDefinition;
import com.dobbinsoft.iotechn.device.exception.DeviceServiceException;
import com.dobbinsoft.iotechn.device.mapper.DeviceDataMapper;
import com.dobbinsoft.iotechn.device.mapper.DeviceMapper;
import com.dobbinsoft.iotechn.device.mapper.ProductDataMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Description:
 * User: rize
 * Date: 2020/6/22
 * Time: 15:33
 */
@Service("deviceBizService")
public class DeviceBizServiceImpl implements DeviceBizService {

    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private DeviceDataMapper deviceDataMapper;

    @Autowired
    private ProductDataMapper productDataMapper;

    @Autowired
    private CacheComponent cacheComponent;

    @Override
    @DS(Const.DB_M)
    @Transactional(rollbackFor = Exception.class)
    public String activeDevice(Long deviceId, Long productId) throws ServiceException {
        // 1. 先更改主表状态
        DeviceDO updateDeviceDO = new DeviceDO();
        updateDeviceDO.setStatus(DeviceStatusType.ONLINE.getCode());
        Date now = new Date();
        updateDeviceDO.setGmtUpdate(now);
        updateDeviceDO.setId(deviceId);
        if (deviceMapper.updateById(updateDeviceDO) > 0) {
            // 2. 为设备添加数据点
            List<ProductDataDO> productDataList = productDataMapper.selectList(new QueryWrapper<ProductDataDO>().eq("product_id", productId));
            List<DeviceDataDO> list = productDataList.stream().map(item -> {
                DeviceDataDO deviceDataDO = new DeviceDataDO();
                deviceDataDO.setDeviceId(deviceId);
                deviceDataDO.setProductDataId(item.getId());
                deviceDataDO.setIdTag(item.getIdTag());
                deviceDataDO.setValue("");
                deviceDataDO.setGmtCreate(now);
                deviceDataDO.setGmtUpdate(now);
                return deviceDataDO;
            }).collect(Collectors.toList());
            if (deviceDataMapper.batchInsert(deviceId, list) > 0) {
                return "ok";
            }
        }
        throw new DeviceServiceException(DeviceExceptionDefinition.DEVICE_UNKNOWN_EXCEPTION);
    }

    @Override
    public String onlineDevice(Long deviceId) {
        deviceMapper.onlineDevice(deviceId, DeviceStatusType.ONLINE.getCode());
        return "ok";
    }

    @Override
    public String offlineDevice(String accessKeyId) {
        deviceMapper.offlineDeviceByAccessKeyId(accessKeyId, DeviceStatusType.OFFLINE.getCode());
        return "ok";
    }

    @Override
    @DS(Const.DB_S)
    public String auth(String ip, String username, String password) throws ServiceException {
        DeviceDO deviceDO = deviceMapper.selectOne(new QueryWrapper<DeviceDO>()
                .select("id", "access_key_id", "access_key_secret", "auth_type")
                .eq("access_key_id", username));
        if (deviceDO == null) {
            throw new DeviceServiceException(DeviceExceptionDefinition.DEVICE_DEVICE_NOT_EXIST);
        }
        // 进行权限鉴定
        if (deviceDO.getAuthType().intValue() == DeviceAuthType.EASY.getCode()) {
            if (!deviceDO.getAccessKeySecret().equals(password)) {
                throw new DeviceServiceException(DeviceExceptionDefinition.DEVICE_PERMISSION_DENY);
            }
        } else if (deviceDO.getAuthType().intValue() == DeviceAuthType.SAFE.getCode()) {
            if (!MD5Util.md5(ip + deviceDO.getAccessKeySecret()).equalsIgnoreCase(password)) {
                throw new DeviceServiceException(DeviceExceptionDefinition.DEVICE_PERMISSION_DENY);
            }
        } else {
            throw new DeviceServiceException(DeviceExceptionDefinition.DEVICE_UNKNOWN_EXCEPTION);
        }
        return "ok";
    }

    @Override
    public List<DeviceDataSnapshotEntity> listDeviceData(Long deviceId) {
        // 获得该设备下所有的数据点值 和 idTag
        Map<String, DeviceSessionDataEntity> map = cacheComponent.getHashAll(DeviceConst.CA_DEVICE_DATA_HASH + deviceId, DeviceSessionDataEntity.class);
        // 获取所有Key
        List<DeviceDataSnapshotEntity> list = map.keySet().stream().map(item -> {
            DeviceDataSnapshotEntity entity = new DeviceDataSnapshotEntity();
            DeviceSessionDataEntity deviceSessionDataEntity = map.get(item);
            entity.setType(deviceSessionDataEntity.getType());
            entity.setValue(deviceSessionDataEntity.getValue());
            entity.setIdTag(item);
            return entity;
        }).collect(Collectors.toList());
        return list;
    }
}
